#include <iostream>
#include <thread>
#include <mutex>
#include <list>
#include <atomic>
#include <condition_variable>

using namespace std;

/*
int x = 0;
mutex m;
list<int> ls;

void func1(int n){
    for (int i = 0; i < n; ++i) {
        m.lock();
        ++x;
        m.unlock();
    }
}

//快：任务太小，没有大量的切换上下文
void func2(int n){
    m.lock();
    for (int i = 0; i < n; ++i) {
        ++x;
    }
    m.unlock();
}

void test1(){
    int n = 1000000;
    size_t begin = clock();

    thread t1(func2, n);
    thread t2(func2, n);
    t1.join();
    t2.join();

    size_t end = clock();
    cout << x << endl;
    cout << end - begin << endl;
}

void func3(int n){
    for (int i = 0; i < n; ++i) {
        m.lock();
        ++x;
        ls.push_back(x);
        m.unlock();

        ls.push_back(x);
        ls.push_back(x);
        ls.push_back(x);

    }
}

void func4(int n){
    m.lock();
    for (int i = 0; i < n; ++i) {
        ++x;
        ls.push_back(x);
        ls.push_back(x);
        ls.push_back(x);
        ls.push_back(x);
    }
    m.unlock();
}

void test2(){
    int n = 100000;
    size_t begin = clock();

    thread t1(func3, n);
    thread t2(func3, n);
    t1.join();
    t2.join();

    size_t end = clock();
    cout << x << endl;
    cout << end - begin << endl;
}
*/

/*
void test(){
    int n = 10000;
    int x = 0;
    mutex m;

    thread t1([&, n](){
        m.lock();
        for (int i = 0; i < n; ++i) {
            ++x;
        }
        m.unlock();
    });

    thread t2([&, n](){
        m.lock();
        for (int i = 0; i < n; ++i) {
            ++x;
        }
        m.unlock();
    });

    t1.join();
    t2.join();

    cout << x << endl;
}
*/

/*
void add1(int& num){
    ++num;
    cout << &num << endl;
}

void test1(){
    int num = 0;
    thread t1(add1, ref(num));
    t1.join();
    cout << num << endl;
    cout << &num << endl;
}

void add2(int* num){
    ++(*num);
    cout << num << endl;
}

void test2(){
    int num = 0;
    thread t1(add2, &num);
    t1.join();
    cout << num << endl;
    cout << &num << endl;
}

void test3(){
    int num = 0;
    thread t1([&num](){
        ++num;
        cout << &num << endl;
    });
    t1.join();
    cout << num << endl;
    cout << &num << endl;
}

void add4(int num){
    ++num;
    cout << &num << endl;
}

void test4(){
    int num = 0;
    thread t1(add4, num);
    t1.join();
    cout << num << endl;
    cout << &num << endl;
}

int x = 0;
void add5(int num){
    ++num;
    cout << &num << endl;
}

void test5(){
    thread t1(add5, x);
    t1.join();
    cout << x << endl;
    cout << &x << endl;
}

int main() {
    test5();
    return 0;
}
*/

/*
class myThread{
public:
    myThread(thread& t):_t(t){

    }
    ~myThread(){
        if (_t.joinable())
            _t.join();
    }
    myThread(const myThread&) = delete;
    myThread& operator=(const myThread&) = delete;
private:
    thread& _t;
};

void func(int n){
    for (int i = 0; i < n; ++i) {
        cout << i << endl;
    }
}

void test(){
    thread t1(func, 3);
    myThread mt(t1);
}

//为保证两个线程使用的是同一个互斥锁：
//1.线程函数以引用方式接收互斥锁，且传参时使用ref保持对互斥锁的引用
//2.将互斥锁定义为全局变量
//3.用lambda表达式定义线程函数，以引用方式捕捉互斥锁

void test1(){
    int x = 0;
    mutex m;
    thread t1([&](){
        m.lock();
        for (int i = 0; i < 100000; ++i) {
            ++x;
        }
        m.unlock();
    });
    thread t2([&](){
        m.lock();
        for (int i = 0; i < 100000; ++i) {
            ++x;
        }
        m.unlock();
    });
    t1.join();
    t2.join();
    cout << x << endl;
}

//使用lock_guard自动加锁解锁
void test2(){
    int x = 0;
    mutex m;
    thread t1([&](){
        {
            lock_guard<mutex> lg(m);
            for (int i = 0; i < 100000; ++i) {
                ++x;
            }
        }
    });
    thread t2([&](){
        {
            lock_guard<mutex> lg(m);
            for (int i = 0; i < 100000; ++i) {
                ++x;
            }
        }
    });
    t1.join();
    t2.join();
    cout << x << endl;
}

//实现lock_guard
namespace luLockGuard{
    template<class Mutex>
    class lockGuard{
    public:
        explicit lockGuard(Mutex& mutex)
        :_mutex(mutex){
            _mutex.lock();
        }
        ~lockGuard(){
            _mutex.unlock();
        }
        lockGuard(const lockGuard&) = delete;
        lockGuard& operator=(const lockGuard&) = delete;
    private:
        Mutex& _mutex;//初始化列表初始化：静态，引用，没有默认
    };
}

void test3(){
    int x = 0;
    mutex m;
    thread t1([&](){
        {
            luLockGuard::lockGuard<mutex> lg(m);
            for (int i = 0; i < 100000; ++i) {
                ++x;
            }
        }
    });
    thread t2([&](){
        {
            luLockGuard::lockGuard<mutex> lg(m);
            for (int i = 0; i < 100000; ++i) {
                ++x;
            }
        }
    });
    t1.join();
    t2.join();
    cout << x << endl;
}

//使用unique_lock
void test4(){
    int x = 0;
    mutex m;
    thread t1([&](){
        unique_lock<mutex> ul(m);//已经加锁，再执行需要先解锁
        ul.unlock();
        for (int i = 0; i < 100000; ++i) {
            ++x;
        }
        ul.lock();
    });
    thread t2([&](){
        unique_lock<mutex> ul(m);
        ul.unlock();
        for (int i = 0; i < 100000; ++i) {
            ++x;
        }
        ul.lock();
    });
    t1.join();
    t2.join();
    cout << x << endl;
}

int main(){
    test4();
    return 0;
}
*/

/*
void func(int& n, int times){
    for (int i = 0; i < times; ++i) {
        ++n;
    }
}

void func1(atomic_int& n, int times){
    for (int i = 0; i < times; ++i) {
        ++n;
    }
}

void test(){
    int n = 0;
    int times = 100000;
    thread t1(func, ref(n), times);
    thread t2(func, ref(n), times);
    t1.join();
    t2.join();
    cout << n << endl;
}

void test1(){
    atomic_int n(0);
    int times = 100000;
    thread t1(func1, ref(n), times);
    thread t2(func1, ref(n), times);
    t1.join();
    t2.join();
    cout << n << endl;
}

void func2(atomic<int>& n, int times){
    for (int i = 0; i < times; ++i) {
        ++n;
    }
}

void test2(){
    atomic<int> n(0);
    int times = 100000;
    thread t1(func1, ref(n), times);
    thread t2(func1, ref(n), times);
    t1.join();
    t2.join();
    cout << n << endl;
    printf("%d\n", n.load());//将原子性的n保存
}

int main(){
    test2();
    return 0;
}
*/

//条件变量

//两个线程交替打印，一个打印奇数，一个打印偶数
void test(){
    mutex m;
    int n = 100;
    int x = 1;

    thread t1([&, n](){
        while (x < n) {
            cout << this_thread::get_id() << ":" << x << endl;
            ++x;
        }
    });
    thread t2([&, n](){
        while (x < n) {
            cout << this_thread::get_id() << ":" << x << endl;
            ++x;
        }
    });
    t1.join();
    t2.join();
}

//1.保证t1先运行，t2阻塞
//2.防止一个线程不断运行

void test1(){
    mutex m;
    condition_variable cv;
    int n = 100;
    int x = 1;

    thread t1([&, n](){
        while (true) {
            unique_lock<mutex> lock(m);
            if (x >= 100)
                break;
            if (x % 2 == 0)
                cv.wait(lock);
            cout << this_thread::get_id() << ":" << x << endl;
            x += 1;
            cv.notify_one();
        }
    });
    thread t2([&, n](){
        while (true) {
            unique_lock<mutex> lock(m);
            if (x > 100)
                break;
            if (x % 2 == 1)
                cv.wait(lock);
            cout << this_thread::get_id() << ":" << x << endl;
            x += 1;
            cv.notify_one();
        }
    });
    t1.join();
    t2.join();
}

void test2(){
    mutex m;
    condition_variable cv;
    int n = 100;
    int x = 1;

    thread t1([&, n](){
        while (true) {
            unique_lock<mutex> lock(m);
            if (x >= 100)
                break;
            cv.wait(lock, [&](){return x % 2 != 0;});//false就wait
            cout << this_thread::get_id() << ":" << x << endl;
            x += 1;
            cv.notify_one();
        }
    });
    thread t2([&, n](){
        while (true) {
            unique_lock<mutex> lock(m);
            if (x > 100)
                break;
            cv.wait(lock, [&](){return x % 2 == 0;});
            cout << this_thread::get_id() << ":" << x << endl;
            x += 1;
            cv.notify_one();
        }
    });
    t1.join();
    t2.join();
}

/*
int main(){
    test2();
    return 0;
}*/
